//
// JsonRpc++ Copyright (c) 2007 by Peter Wang
//
#ifndef _JSONRPCSERVERMETHOD_H_
#define _JSONRPCSERVERMETHOD_H_

#if defined(_MSC_VER)
# pragma warning(disable:4786)    // identifier was truncated in debug info
#endif

#ifndef MAKEDEPEND
# include <string>
#endif

#include "json\\Json.h"
#include "JsonRpcUtil.h"

namespace JsonRpc {

  // The JsonRpcServer processes client requests to call RPCs
  class JsonRpcServer;

  //! Abstract class representing a single RPC method
  class JsonRpcServerMethod {
  public:
    //! Constructor
    JsonRpcServerMethod(std::string const& name, JsonRpcServer* server = 0);
    //! Destructor
    virtual ~JsonRpcServerMethod();

    //! Returns the name of the method
    std::string& name() { return _name; }

    //! Execute the method. Subclasses must provide a definition for this method.
    virtual void execute(Json::Value& params, Json::Value& result) = 0;

    //! Returns a help string for the method.
    //! Subclasses should define this method if introspection is being used.
    virtual std::string help() { return std::string(); }

  protected:
    std::string _name;
    JsonRpcServer* _server;
  };

  namespace Wrapper {

    class WrapperBase : public JsonRpcServerMethod
    {
    public:
        WrapperBase(JsonRpcServer* s, std::string const& methodName, std::string const& help="", const void *context=NULL) ;
        std::string help() { return _help; }
    protected:
        void _checkArgc(Json::Value& params, unsigned int expected);
        void _reportTypeError(int index, std::string s);
        void _checkType(Json::Value & params, int index, int *);
        void _checkType(Json::Value & params, int index, unsigned int *);
        void _checkType(Json::Value & params, int index, double *);
        void _checkType(Json::Value & params, int index, std::string *);
        void _checkType(Json::Value & params, int index, const char **);
        void _checkType(Json::Value & params, int index, bool *);
        void _checkType(Json::Value & params, int index, Json::Value *);

        std::string _help;
        const void *_context;
    } ;

#define checkArgv_0(params, n)  _checkArgc(params, n)
#define checkArgv_1(params, n)  checkArgv_0(params, n) ; _checkType(params, 0, (T1 *) 0)
#define checkArgv_2(params, n)  checkArgv_1(params, n) ; _checkType(params, 1, (T2 *) 0)
#define checkArgv_3(params, n)  checkArgv_2(params, n) ; _checkType(params, 2, (T3 *) 0)
#define checkArgv_4(params, n)  checkArgv_3(params, n) ; _checkType(params, 3, (T4 *) 0)
#define checkArgv_5(params, n)  checkArgv_4(params, n) ; _checkType(params, 4, (T5 *) 0)
#define checkArgv_6(params, n)  checkArgv_5(params, n) ; _checkType(params, 5, (T6 *) 0)
#define checkArgv_7(params, n)  checkArgv_6(params, n) ; _checkType(params, 6, (T7 *) 0)

#define callParams_0(params) 
#define callParams_1(params)  impl::getValue<T1>(params[0U])
#define callParams_2(params)  callParams_1(params), impl::getValue<T2>(params[1])
#define callParams_3(params)  callParams_2(params), impl::getValue<T3>(params[2])
#define callParams_4(params)  callParams_3(params), impl::getValue<T4>(params[3])
#define callParams_5(params)  callParams_4(params), impl::getValue<T5>(params[4])
#define callParams_6(params)  callParams_5(params), impl::getValue<T6>(params[5])
#define callParams_7(params)  callParams_6(params), impl::getValue<T7>(params[6])

#define CALL_FUNCTION(params, result, n)  checkArgv_##n(params, n); result = _function(callParams_##n(params))
#define CALL_METHOD(params, result , n)   checkArgv_##n(params, n); result = (_obj->*_function)(callParams_##n(params))

    template < class R >
    class FunctionWrapper0: public WrapperBase
    {
    typedef R(* FunctionType)();
    public:
        FunctionWrapper0(JsonRpcServer* s, std::string const& methodName, 
            FunctionType fun, 
            std::string const& help, const void *context) 
            :WrapperBase(s, methodName, help, context), _function(fun)
        {
        }
        void execute(Json::Value& params, Json::Value& result)
        {
            CALL_FUNCTION(params, result, 0);
        }
    private:
        FunctionType  _function;
    };

    template < class R , class T1>
    class FunctionWrapper1: public WrapperBase
    {
     typedef R(*FunctionType)(T1);
    public:
        FunctionWrapper1(JsonRpcServer* s, std::string const& methodName, 
            FunctionType fun, 
            std::string const& help, const void *context) 
            :WrapperBase(s, methodName, help, context), _function(fun)
        {
        }
        void execute(Json::Value& params, Json::Value& result)
        {
            CALL_FUNCTION(params, result, 1);
        }

    private:
        FunctionType  _function;
    };

    template < class R , class T1, class T2>
    class FunctionWrapper2: public WrapperBase
    {
     typedef R(*FunctionType)(T1, T2);
    public:
        FunctionWrapper2(JsonRpcServer* s, std::string const& methodName, 
            FunctionType fun, 
            std::string const& help, const void *context) 
            :WrapperBase(s, methodName, help, context), _function(fun)
        {
        }
        void execute(Json::Value& params, Json::Value& result)
        {
            CALL_FUNCTION(params, result, 2);
        }

    private:
        FunctionType  _function;
    };

    template < class R , class T1, class T2, class T3>
    class FunctionWrapper3: public WrapperBase
    {
    typedef R(*FunctionType)(T1, T2, T3);
    public:
        FunctionWrapper3(JsonRpcServer* s, std::string const& methodName, 
            FunctionType fun, 
            std::string const& help, const void *context) 
            :WrapperBase(s, methodName, help, context), _function(fun)
        {
        }
        void execute(Json::Value& params, Json::Value& result)
        {
            CALL_FUNCTION(params, result, 3);
        }

    private:
        FunctionType  _function;
    };

    template < class R , class T1, class T2, class T3, class T4>
    class FunctionWrapper4: public WrapperBase
    {
    typedef R(*FunctionType)(T1, T2, T3, T4);
    public:
        FunctionWrapper4(JsonRpcServer* s, std::string const& methodName, 
            FunctionType fun, 
            std::string const& help, const void *context) 
            :WrapperBase(s, methodName, help, context), _function(fun)
        {
        }
        void execute(Json::Value& params, Json::Value& result)
        {
            CALL_FUNCTION(params, result, 4);
        }

    private:
        FunctionType  _function;
    };

    template < class R , class T1, class T2, class T3, class T4, class T5>
    class FunctionWrapper5: public WrapperBase
    {
    typedef R(*FunctionType)(T1, T2, T3, T4, T5);
    public:
        FunctionWrapper5(JsonRpcServer* s, std::string const& methodName, 
            FunctionType fun, 
            std::string const& help, const void *context) 
            :WrapperBase(s, methodName, help, context), _function(fun)
        {
        }
        void execute(Json::Value& params, Json::Value& result)
        {
            CALL_FUNCTION(params, result, 5);
        }

    private:
        FunctionType  _function;
    };

    template < class R , class T1, class T2, class T3, class T4, class T5, class T6>
    class FunctionWrapper6: public WrapperBase
    {
    typedef R(*FunctionType)(T1, T2, T3, T4, T5, T6);
    public:
        FunctionWrapper6(JsonRpcServer* s, std::string const& methodName, 
            FunctionType fun,
            std::string const& help, const void *context) 
            :WrapperBase(s, methodName, help, context), _function(fun)
        {
        }
        void execute(Json::Value& params, Json::Value& result)
        {
            CALL_FUNCTION(params, result, 6);
        }

    private:
        FunctionType  _function;
    };

    template < class R , class T1, class T2, class T3, class T4, class T5, class T6, class T7>
    class FunctionWrapper7: public WrapperBase
    {
    typedef R(*FunctionType)(T1, T2, T3, T4, T5, T6, T7);
    public:
        FunctionWrapper7(JsonRpcServer* s, std::string const& methodName, 
           FunctionType fun, 
            std::string const& help, const void *context) 
            :WrapperBase(s, methodName, help, context), _function(fun)
        {
        }
        void execute(Json::Value& params, Json::Value& result)
        {
            CALL_FUNCTION(params, result, 7);
        }

    private:
        FunctionType  _function;
    };


   template < class A, class R >
    class MethodWrapper0: public WrapperBase
    {
    typedef R(A::*FunctionType)();
    public:
        MethodWrapper0(JsonRpcServer* s, std::string const& methodName, 
           A*  obj,  FunctionType fun, 
            std::string const& help) 
            :WrapperBase(s, methodName, help), _function(fun), _obj(obj)
        {
        }
        void execute(Json::Value& params, Json::Value& result)
        {
            CALL_METHOD(params, result, 0);
        }
    private:
        FunctionType  _function;
       A* _obj;
    };

    template < class A, class R , class T1>
    class MethodWrapper1: public WrapperBase
    {
    typedef R(A::*FunctionType)(T1);
    public:
        MethodWrapper1(JsonRpcServer* s, std::string const& methodName, 
           A*  obj,  FunctionType fun, 
            std::string const& help) 
            :WrapperBase(s, methodName, help), _function(fun), _obj(obj)
        {
        }
        void execute(Json::Value& params, Json::Value& result)
        {
            CALL_METHOD(params, result, 1);
        }

    private:
        FunctionType  _function;
       A* _obj;
    };

    template < class A, class R , class T1, class T2>
    class MethodWrapper2: public WrapperBase
    {
    typedef R(A::*FunctionType)(T1, T2);
    public:
        MethodWrapper2(JsonRpcServer* s, std::string const& methodName, 
           A*  obj,  FunctionType fun, 
            std::string const& help) 
            :WrapperBase(s, methodName, help), _function(fun), _obj(obj)
        {
        }
        void execute(Json::Value& params, Json::Value& result)
        {
            CALL_METHOD(params, result, 2);
        }

    private:
        FunctionType  _function;
       A* _obj;
    };

    template < class A, class R , class T1, class T2, class T3>
    class MethodWrapper3: public WrapperBase
    {
    typedef R(A::*FunctionType)(T1, T2, T3);
    public:
        MethodWrapper3(JsonRpcServer* s, std::string const& methodName, 
           A*  obj,  FunctionType fun, 
            std::string const& help) 
            :WrapperBase(s, methodName, help), _function(fun), _obj(obj)
        {
        }
        void execute(Json::Value& params, Json::Value& result)
        {
            CALL_METHOD(params, result, 3);
        }

    private:
        FunctionType  _function;
       A* _obj;
    };

    template < class A, class R , class T1, class T2, class T3, class T4>
    class MethodWrapper4: public WrapperBase
    {
    typedef R(A::*FunctionType)(T1, T2, T3, T4 );
    public:
        MethodWrapper4(JsonRpcServer* s, std::string const& methodName, 
           A*  obj,  FunctionType fun, 
            std::string const& help) 
            :WrapperBase(s, methodName, help), _function(fun), _obj(obj)
        {
        }
        void execute(Json::Value& params, Json::Value& result)
        {
            CALL_METHOD(params, result, 4);
        }

    private:
        FunctionType  _function;
       A* _obj;
    };

    template < class A, class R , class T1, class T2, class T3, class T4, class T5>
    class MethodWrapper5: public WrapperBase
    {
    typedef R(A::*FunctionType)(T1, T2, T3, T4, T5 );
    public:
        MethodWrapper5(JsonRpcServer* s, std::string const& methodName, 
           A*  obj,  FunctionType fun, 
            std::string const& help) 
            :WrapperBase(s, methodName, help), _function(fun), _obj(obj)
        {
        }
        void execute(Json::Value& params, Json::Value& result)
        {
            CALL_METHOD(params, result, 5);
        }

    private:
        FunctionType  _function;
       A* _obj;
    };

    template < class A, class R , class T1, class T2, class T3, class T4, class T5, class T6>
    class MethodWrapper6: public WrapperBase
    {
    typedef R(A::*FunctionType)(T1, T2, T3, T4, T5, T6);
    public:
        MethodWrapper6(JsonRpcServer* s, std::string const& methodName, 
           A*  obj,  FunctionType fun,
            std::string const& help) 
            :WrapperBase(s, methodName, help), _function(fun), _obj(obj)
        {
        }
        void execute(Json::Value& params, Json::Value& result)
        {
            CALL_METHOD(params, result, 6);
        }

    private:
        FunctionType  _function;
       A* _obj;
    };

    template < class A, class R , class T1, class T2, class T3, class T4, class T5, class T6, class T7>
    class MethodWrapper7: public WrapperBase
    {
    typedef R(A::*FunctionType)(T1, T2, T3, T4, T5, T6, T7);
    public:
        MethodWrapper7(JsonRpcServer* s, std::string const& methodName, 
           A*  obj,  FunctionType fun, 
            std::string const& help) 
            :WrapperBase(s, methodName, help), _function(fun), _obj(obj)
        {
        }
        void execute(Json::Value& params, Json::Value& result)
        {
            CALL_METHOD(params, result, 7);
        }

    private:
        FunctionType  _function;
       A* _obj;
    };
#undef checkArgv_0
#undef checkArgv_1
#undef checkArgv_2
#undef checkArgv_3
#undef checkArgv_4
#undef checkArgv_5
#undef checkArgv_6
#undef checkArgv_7
#undef callParams_0
#undef callParams_1
#undef callParams_2
#undef callParams_3
#undef callParams_4
#undef callParams_5
#undef callParams_6
#undef callParams_7
#undef CALL_FUNCTION
#undef CALL_METHOD
  }  // namespace Wrapper
} // namespace JsonRpc

#endif // _JSONRPCSERVERMETHOD_H_
